#include "viewer.h"

#include <string>
#include <iostream>

#ifdef _MAC_OS_
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#endif

#include <climits>

using namespace std;

Viewer::Viewer():
  _halfSize(0.5),
  _growing(true)
  {


}


Viewer::~Viewer(){

}


////////////////////////////////////////////////////////////////////////////////
// GL stuff

// initialize OpenGL context
void
Viewer::init(int w, int h)
{

	// Initialisation possible :
	// vec3f color(1.0) -> produira du rouge car les deux autres paramètres sont mis à 0
	_square.pos() = vec2f(-0.2,-0.3);
	_square.dim() = vec2f(0.3,0.3);
	_square.color() = vec3f(1.0) ;

	// background color
	glClearColor (0.0, 0.0, 0.0, 1.0);

	// viewport
	glViewport (0, 0, w, h);
}

void
Viewer::reshape(int w, int h){
  glViewport (0, 0, w, h);
}


/*!
   callback to draw graphic primitives
   you may edit it if you want to change de drawing procedure (add new objects
   for example).
 */
void
Viewer::display() const{
  // clear current buffer
  glClear (GL_COLOR_BUFFER_BIT);

  // define projetion matrix
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (-1.1, 1.1, -1.1, 1.1, -10, 10);

  // define model view matrix
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  /////////////////////////////////////
  // Draw the primitives.
  //
  _square.draw();
  //
  // End of drawing
  /////////////////////////////////////

  glFlush();
}


void
Viewer::updateScene () {
	if (_growing)
	{ // grow square
		_square.grow();
		_growing = _square.dim().x() < 0.7; // grow square until _halfSize >= 0.8
	}
	else
	{
		_square.shrink();
		_growing = _square.dim().x() < 0.4;// grow square until _halfSize <= 0.3
	}



   	std::mt19937 rng;
	auto unix_timestamp = std::chrono::seconds(std::time(NULL));
	int timestamp = std::chrono::milliseconds(unix_timestamp).count();

	rng.seed(timestamp);
	double coeff = 1.0 / (INT_MAX * 10000.0);

	if(rng() % 3 == 0)
	{
		_square.setSpeed( rng() * coeff, rng() * coeff);
	}
	_square.update();

	display();
}


////////////////////////////////////////////////////////////////////////////////
// Events

/*!
   callback to manage mouse : called when user press or release mouse button
   You can change in this function the way the user
   interact with the system.
 */
void
Viewer::mousePressed(int button, int state, int x, int y){
   std::string buttonName;

   switch(button){
   case GLUT_LEFT_BUTTON:
      buttonName = string("left");
      break;
   case GLUT_MIDDLE_BUTTON:
      buttonName = string("middle");
      break;
   case GLUT_RIGHT_BUTTON:
      buttonName = string("right");
      break;
   default:
      buttonName = string("invalid");
   }

   cout << "User "
        << (state == GLUT_DOWN ? "press " : "release ")
        << buttonName.c_str()
        << " button in "
        << x
        << ", "
        << y
        << endl;

	GLint m_viewport[4];
	glGetIntegerv( GL_VIEWPORT, m_viewport );

	// 1. Vecteur distance
	vec2f speed{
		(float)( (2.0 * x - m_viewport[2]) / m_viewport[2] - (_square.pos().x() + _square.dim().x() / 2.0)),
		(float)(-(2.0 * y - m_viewport[3]) / m_viewport[3] - (_square.pos().y() + _square.dim().y() / 2.0))};

	// 2. Normalisation
	speed.normalize();

	// 3. Réduction
	speed /= 1000.0f;
	_square.setSpeed(speed);


   // request display refresh
   glutPostRedisplay();
}




/*!
   callback to manage mouse : called when user move mouse with button pressed
   You can change in this function the way the user
   interact with the system.
 */
void
Viewer::mouseMoved(int x, int y){
     cout << "Mouse moved in "
        << x
        << ", "
        << y
        << endl;

	GLint m_viewport[4];
	glGetIntegerv( GL_VIEWPORT, m_viewport );

	// 1. Vecteur distance
	vec2f speed{
		(float)( (2.0 * x - m_viewport[2]) / m_viewport[2] - (_square.pos().x() + _square.dim().x() / 2.0)),
		(float)(-(2.0 * y - m_viewport[3]) / m_viewport[3] - (_square.pos().y() + _square.dim().y() / 2.0))};

	// 2. Normalisation
	speed.normalize();

	// 3. Réduction
	speed /= 1000.0f;
	_square.setSpeed(speed);


   // request display refresh
   glutPostRedisplay();
}


/*!
   callback to manage keyboard interactions
   You can change in this function the way the user
   interact with the system.
 */
void
Viewer::keyPressed(unsigned char key, int x, int y){

}
